export interface ImageStyle {
  width: number | string;
  height: number | string;
  top: number;
  left: number;
  transform: string;
  transition: string;
}
export interface DefaultOptions {
  // 图片盒子的宽高
  imgBox: { width: number; height: number };
  // 图片元素
  img: UniApp.GetImageInfoSuccessData | null;

  // 开始的两个触点的初始距离 - 已经旋转的角度
  startDst: number;
  // 开始的两个触点的初始角度  / 已经缩放比例
  startDeg: number;
  // 图片的中心点
  startCentreX: number;
  startCentreY: number;
  // 图片的左上角
  startX: number;
  startY: number;

  // 开始img的top和left
  startTop: number;
  startLeft: number;

  // 开始的宽高
  startHeight: number;
  startWidth: number;
  // 开始的两个触点的中点
  startZhong: { x: number; y: number };

  // 图片的高度和宽度
  imgWidth: number;
  imgHeight: number;
  imgStyle: ImageStyle;
}
export interface Options {
  // 旋转角度
  deg: number;
  //手机两指是否可以旋转
  degIf: boolean;
  // 缩放的比例
  scale: number;
  minScale: number;
  maxScale: number;
  // 图片地址
  imgUrl: string | null;
  // 图片容器id，默认 #img-container
  containerId: string;
  judgeImageOver: boolean;
}

export interface OptionsAll extends DefaultOptions, Options {}
export class PreviewImage {
  optionsAll: OptionsAll;
  constructor() {
    this.optionsAll = {
      degIf: false,
      imgBox: { width: 0, height: 0 },
      imgUrl: null,
      containerId: "#img-container",
      img: null,
      scale: 1,
      minScale: 0.5,
      maxScale: 20,
      deg: 0,
      startDst: 0,
      startDeg: 0,
      startCentreX: 0,
      startCentreY: 0,
      startX: 0,
      startY: 0,
      startLeft: 0,
      startTop: 0,
      startHeight: 0,
      startWidth: 0,
      startZhong: { x: 0, y: 0 },
      imgWidth: 0,
      imgHeight: 0,
      judgeImageOver: false,
      imgStyle: {
        width: "100%",
        height: "100%",
        left: 0,
        top: 0,
        transform: "rotate(0deg)",
        transition: "",
      },
    };
  }

  async init(options: Options) {
    if (!options.imgUrl) {
      throw new Error("图片地址不能为空");
    }

    this.optionsAll = {
      ...this.optionsAll,
      ...options,
    };

    if (options.deg === 0) {
      this.optionsAll.imgStyle.transform = "rotate(0deg)";
    }

    await this.getImageInfo();
  }

  /**
   * @description: 获取图片信息
   */
  async getImageInfo() {
    if (this.optionsAll.imgUrl) {
      uni.getImageInfo({
        src: this.optionsAll.imgUrl,
        success: (image) => {
          console.log("success", image);
          this.optionsAll.img = image;
          this.optionsAll.imgWidth = image.width;
          this.optionsAll.imgHeight = image.height;
          this.getRectInfo();
        },
        fail: (err) => {
          console.log("err", err);
        },
      });
    }
  }

  /**
   * @description: 获取图片容器信息
   */
  async getRectInfo() {
    const query = uni.createSelectorQuery();
    query
      .select(this.optionsAll.containerId)
      .boundingClientRect((rect) => {
        if (rect) {
          this.optionsAll.imgBox.width = (rect as UniApp.NodeInfo).width!;
          this.optionsAll.imgBox.height = (rect as UniApp.NodeInfo).height!;
          this.judgeImgWidthOrHeight();
        }
      })
      .exec();
  }

  /**
   * @description: 判断图片的宽高，(高>宽：图片以高为准；宽>高：图片以宽为准)
   */
  judgeImgWidthOrHeight() {
    const imgWidth = this.optionsAll.imgWidth;
    const imgHeight = this.optionsAll.imgHeight;
    const imgBoxWidth = this.optionsAll.imgBox.width;
    const imgBoxHeight = this.optionsAll.imgBox.height;
    if (imgWidth > imgHeight) {
      this.optionsAll.imgStyle.height = (imgHeight / imgWidth) * imgBoxWidth;
      this.optionsAll.imgStyle.width = imgBoxWidth;
      this.optionsAll.imgStyle.left = 0;
      this.optionsAll.imgStyle.top =
        imgBoxHeight / 2 - this.optionsAll.imgStyle.height / 2;
    } else {
      this.optionsAll.imgStyle.width =
        (imgWidth / imgHeight) * (imgBoxHeight - 70);
      if (this.optionsAll.imgStyle.width > imgBoxWidth) {
        this.optionsAll.imgStyle.height = (imgHeight / imgWidth) * imgBoxWidth;
        this.optionsAll.imgStyle.width = imgBoxWidth;
        this.optionsAll.imgStyle.left = 0;
        this.optionsAll.imgStyle.top =
          imgBoxHeight / 2 - this.optionsAll.imgStyle.height / 2;
      } else {
        this.optionsAll.imgStyle.height = imgBoxHeight - 70;
        this.optionsAll.imgStyle.top = 0;
        this.optionsAll.imgStyle.left =
          imgBoxWidth / 2 - this.optionsAll.imgStyle.width / 2;
      }
    }
    this.optionsAll.imgWidth = this.optionsAll.imgStyle.width;
    this.optionsAll.imgHeight = this.optionsAll.imgStyle.height;
    this.optionsAll.judgeImageOver = true;
  }

  /**
   * @description: 处理touchstart事件
   */
  handleTouchStart(event: TouchEvent) {
    if (event.touches.length >= 2) {
      //阻止浏览器默认行为
      event.preventDefault();

      //计算一下两个触点的初始角度 - 已经旋转的角度
      this.optionsAll.startDeg =
        this.getDeg(event.touches[0], event.touches[1]) - this.optionsAll.deg;
      //计算一下两个触点的初始距离 / 已经缩放比例
      this.optionsAll.startDst =
        this.getDst(event.touches[0], event.touches[1]) / this.optionsAll.scale;

      this.optionsAll.startTop = this.optionsAll.imgStyle.top as number;
      this.optionsAll.startLeft = this.optionsAll.imgStyle.left as number;
      //获取两触点的中点
      this.optionsAll.startZhong = this.getZhong(
        event.touches[0],
        event.touches[1]
      );

      //开始的宽高
      this.optionsAll.startHeight =
        this.optionsAll.scale * this.optionsAll.imgHeight;
      this.optionsAll.startWidth =
        this.optionsAll.scale * this.optionsAll.imgWidth;

      //计算两触点 中点 在图片上的比例
      this.optionsAll.startCentreY =
        (this.optionsAll.startZhong.y - this.optionsAll.startTop) /
        this.optionsAll.startHeight;
      this.optionsAll.startCentreX =
        (this.optionsAll.startZhong.x - this.optionsAll.startLeft) /
        this.optionsAll.startWidth;
    } else if (event.touches.length == 1) {
      this.optionsAll.startX = event.touches[0].clientX;
      this.optionsAll.startY = event.touches[0].clientY;
      this.optionsAll.startTop = this.optionsAll.imgStyle.top as number;
      this.optionsAll.startLeft = this.optionsAll.imgStyle.left as number;
    }
  }

  /**
   * @description: 处理touchmove事件
   */
  handleTouchMove(event: TouchEvent) {
    if (event.touches.length >= 2) {
      // 计算当前两个触点的距离
      const currentDst = this.getDst(event.touches[0], event.touches[1]);
      const currentZhong = this.getZhong(event.touches[0], event.touches[1]);
      // 计算当前两个触点的距离 和 两个触点的初始距离 的 比例
      this.optionsAll.scale = currentDst / this.optionsAll.startDst;

      if (this.optionsAll.scale < this.optionsAll.minScale) {
        this.optionsAll.scale = this.optionsAll.minScale;
        return;
      }
      if (this.optionsAll.scale > this.optionsAll.maxScale) {
        this.optionsAll.scale = this.optionsAll.maxScale;
        return;
      }

      const newW = this.optionsAll.scale * this.optionsAll.imgWidth;
      const newH = this.optionsAll.scale * this.optionsAll.imgHeight;

      //按照比例进行缩放
      this.optionsAll.imgStyle.width = newW;
      this.optionsAll.imgStyle.height = newH;
      //中点的坐标 移动 的距离
      const ztop = currentZhong.y - this.optionsAll.startZhong.y;
      const zleft = currentZhong.x - this.optionsAll.startZhong.x;

      //获取增加的高度 * 中点在图片上的比例 再加上 中点移动的坐标
      this.optionsAll.imgStyle.top =
        this.optionsAll.startTop -
        (newH - this.optionsAll.startHeight) * this.optionsAll.startCentreY +
        ztop;
      this.optionsAll.imgStyle.left =
        this.optionsAll.startLeft -
        (newW - this.optionsAll.startWidth) * this.optionsAll.startCentreX +
        zleft;

      //旋转
      if (this.optionsAll.degIf) {
        const currentDeg = this.getDeg(event.touches[0], event.touches[1]);
        this.optionsAll.deg = currentDeg - this.optionsAll.startDeg;
        // img.style.transformOrigin = startCentreX * 100 +'%, '+startCentreY * 100 +'%';
        this.optionsAll.imgStyle.transform =
          "rotate(" + this.optionsAll.deg + "deg)";
      }
    } else if (event.touches.length == 1) {
      const X = event.touches[0].clientX - this.optionsAll.startX;
      const Y = event.touches[0].clientY - this.optionsAll.startY;
      this.optionsAll.imgStyle.left = X + this.optionsAll.startLeft;
      this.optionsAll.imgStyle.top = Y + this.optionsAll.startTop;
    }
  }

  /**
   * @description: 处理touchend事件
   */
  handleTouchEnd(event: TouchEvent) {
    const { imgStyle } = this.optionsAll;
    if (event.touches.length == 1) {
      //从两指变成一指， 要重置 触点的坐标 和 img的top和left ，不然会乱飙
      this.optionsAll.startX = event.touches[0].clientX;
      this.optionsAll.startY = event.touches[0].clientY;
      this.optionsAll.startTop = imgStyle.top as number;
      this.optionsAll.startLeft = imgStyle.left as number;
    }
  }

  /**
   * 计算两个触点的位置
   * @param touch1 第一个触点
   * @param touch2 第二个触点
   */
  getDst(touch1: Touch, touch2: Touch) {
    //计算两个直角边的长度
    const x = touch2.clientX - touch1.clientX; //水平方向的距离
    const y = touch2.clientY - touch1.clientY; //垂直方向的距离
    //利用勾股定理，计算两个触点的距离（斜边的长度）
    const z = Math.sqrt(x * x + y * y);
    // 返回结果
    return z;
  }

  /**
   * 计算两个触点的夹角（水平辅助线）的角度
   * @param touch1 第一个触点
   * @param touch2 第二个触点
   */
  getDeg(touch1: Touch, touch2: Touch) {
    //计算两个触点的距离，两个直角边长度
    const x = touch2.clientX - touch1.clientX; //临边
    const y = touch2.clientY - touch1.clientY; //对边
    //根据两个直角边比例 tan，计算角度
    const angle = Math.atan2(y, x); //是个弧度
    //根据弧度计算角度
    const deg = (angle / Math.PI) * 180;
    //返回角度
    return deg;
  }

  /**
   * 计算两个触点的中点
   * @param touch1 第一个触点
   * @param touch2 第二个触点
   */
  getZhong(touch1: Touch, touch2: Touch) {
    const dd = { x: 0, y: 0 };
    dd.x = Math.abs(touch2.clientX + touch1.clientX) / 2; //水平方向的距离
    dd.y = Math.abs(touch2.clientY + touch1.clientY) / 2; //垂直方向的距离
    // 返回结果
    return dd;
  }

  /**
   * @description: 左旋
   */
  rotateLeft() {
    this.optionsAll.deg -= 90;
    this.upRotate();
  }

  /**
   * @description: 右旋
   */
  rotateRight() {
    this.optionsAll.deg += 90;
    this.upRotate();
  }

  /**
   * @description: 更新旋转
   */
  upRotate() {
    const { deg } = this.optionsAll;
    const timer = 0.3;
    this.optionsAll.imgStyle.transition = `transform ${timer}s`;
    this.optionsAll.imgStyle.transform = "rotate(" + deg + "deg)";
    setTimeout(() => {
      this.optionsAll.imgStyle.transition = ``;
    }, timer * 1000);
  }

  /**
   * @description: 抛出图片样式
   */
  getImgStyle() {
    const { imgStyle } = this.optionsAll;
    return imgStyle;
  }

  /**
   * @description: 抛出图片宽高获取完成状态
   */
  getJudgeImageOver() {
    return this.optionsAll.judgeImageOver;
  }
}
